/**
 * @file bsp_spi_bus.c
 * @author your name (you@domain.com)
 * @brief SPI总线收发数据底层驱动
 * @version 0.1
 * @date 2022-03-25
 * 
 * @copyright Copyright (c) 2022
 * 
 */

#include "spi_config.h"
#include "gpio_config.h"
#include "bsp_spi_bus.h"
#include "bsp.h"

// HAL_GPIO_WritePin(JOINT_ENC_CS_GPIO_Port, JOINT_ENC_CS_Pin, SET);
// HAL_GPIO_WritePin(JOINT_ENC_CS_GPIO_Port, JOINT_ENC_CS_Pin, RESET);
#define JOINT_ENC_SELECT (JOINT_ENC_CS_GPIO_Port->BSRR = (uint32_t)JOINT_ENC_CS_Pin << 16U)
#define JOINT_ENC_UNSELECT (JOINT_ENC_CS_GPIO_Port->BSRR = JOINT_ENC_CS_Pin)

#define PR_ENC_SELECT (PR_CS_GPIO_Port->BSRR = (uint32_t)PR_CS_Pin << 16U)
#define PR_ENC_UNSELECT (PR_CS_GPIO_Port->BSRR = PR_CS_Pin)

#define FRAM_DEV_SELECT (FRAM_CS_GPIO_Port->BSRR = (uint32_t)FRAM_CS_Pin << 16U)
#define FRAM_DEV_UNSELECT (FRAM_CS_GPIO_Port->BSRR = FRAM_CS_Pin)

#define OUTER_FLASH_DEV_SELECT (OUTER_FRAM_CS_GPIO_Port->BSRR = (uint32_t)OUTER_FLASH_CS_Pin << 16U)
#define OUTER_FLASH_DEV_UNSELECT (OUTER_FRAM_CS_GPIO_Port->BSRR = OUTER_FLASH_CS_Pin)

enum
{
    TRANSFER_WAIT = 0,
    TRANSFER_COMPLETE,
    TRANSFER_ERROR
};

enum
{
    IDLE = 0,
    BUSY
};

volatile spi_bus_inst_t g_spi_ctrl[SPI_TOTAL_NUM];

/**
 * @brief 根据SPI序号绑定对应对应SPI
 * 
 * @param spi_index spi索引,取值范围 0 到 SPI_TOTAL_NUM - 1 
 * @return int16_t 返回SPI控制器数组的索引，取值范围0 到 SPI_TOTAL_NUM-1
 */
int16_t bsp_getSpiIndex(uint8_t spi_index)
{
    return ((spi_index < SPI_TOTAL_NUM) ? spi_index : 0);
}

/**
 * @brief 配置SPI总线
 * 
 * @param spi_id spi索引,取值范围 0 到 SPI_TOTAL_NUM - 1 
 */
void bsp_initSpiBus(uint8_t spi_id)
{
    int16_t spi_index = bsp_getSpiIndex(spi_id);

    g_spi_ctrl[spi_index].is_busy = IDLE;
    // 如果多个不同的SPI器件挂在一根总线上，可以根据不同的器件指定其合适的模式及速率
    // bsp_InitSPIParam(spi_index, SPI_BAUDRATEPRESCALER_8, SPI_PHASE_1EDGE, SPI_POLARITY_LOW);
}

#define SPI_TX_BUF (p_spi_bus_inst->tx_buf)
#define SPI_RX_BUF (p_spi_bus_inst->rx_buf)
#define DATA_LEN (p_spi_bus_inst->data_len)

/**
 * @brief 启动数据传输
 * 
 * @param spi_id spi索引,取值范围 0 到 SPI_TOTAL_NUM - 1 
 */
void bsp_spiTransfer(uint8_t spi_id)
{
    int16_t spi_index = bsp_getSpiIndex(spi_id);
    volatile spi_bus_inst_t *p_spi_bus_inst = &g_spi_ctrl[spi_index];

    if (DATA_LEN > SPI_BUFFER_SIZE)
    {
        return;
    }
    /* 中断方式传输 */
#ifdef USE_SPI_INT
    p_spi_bus_inst->tx_state = TRANSFER_WAIT;

    if (HAL_SPI_TransmitReceive_IT(&hspix[spi_index], (uint8_t *)SPI_TX_BUF, (uint8_t *)SPI_RX_BUF, DATA_LEN) != HAL_OK)
    {
        Error_Handler(__FILE__, __LINE__);
    }

    while (p_spi_bus_inst->tx_state == TRANSFER_WAIT)
    {
		// TODO: 增加超时检测代码，当检测到p_spi_bus_inst->is_busy为1且超时后可重设p_spi_bus_inst->tx_state为TRANSFER_COMPLETE或TRANSFER_ERROR
        ;
    }
#endif

    //     /* DMA方式传输 */
    // #ifdef USE_SPI_DMA
    //     wTransferState = TRANSFER_WAIT;

    //     if (HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t *)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)
    //     {
    //         Error_Handler(__FILE__, __LINE__);
    //     }

    //     while (wTransferState == TRANSFER_WAIT)
    //     {
    //         ;
    //     }
    // #endif

    //     /* 查询方式传输 */
    // #ifdef USE_SPI_POLL
    //     if (HAL_SPI_TransmitReceive(&hspi, (uint8_t *)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)
    //     {
    //         Error_Handler(__FILE__, __LINE__);
    //     }
    // #endif
}


/**
 * @brief SPI数据传输完成回调
 * 
 * @param hspi SPI_HandleTypeDef 类型指针变量
 */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if (hspi->Instance == ENC_SPI)
    {
        g_spi_ctrl[ENC_SPI_INDEX].tx_state = TRANSFER_COMPLETE;
    }
    if (hspi->Instance == STORAGE_SPI)
    {
        g_spi_ctrl[STORAGE_SPI_INDEX].tx_state = TRANSFER_COMPLETE;
    }
}

/**
 * @brief SPI数据传输错误回调
 * 
 * @param hspi SPI_HandleTypeDef 类型指针变量
 */
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
    if (hspi->Instance == ENC_SPI)
    {
        g_spi_ctrl[ENC_SPI_INDEX].tx_state = TRANSFER_ERROR;
    }
    if (hspi->Instance == STORAGE_SPI)
    {
        g_spi_ctrl[STORAGE_SPI_INDEX].tx_state = TRANSFER_ERROR;
    }
}

/**
 * @brief 占用SPI总线，拉低对应片选
 * 0 表示不忙  1表示忙
 * @param spi_id SPI总线序号
 * @param device_id 设备序号
 */
void bsp_spiBusEnter(uint8_t spi_id, uint8_t device_id)
{
    // 增加了入口参数device_id，使得在一条SPI总线上可以挂多个设备
    int16_t spi_index = bsp_getSpiIndex(spi_id);
    if (ENC_SPI_INDEX == spi_index)
    {
        switch (device_id)
        {
        case 1:
            JOINT_ENC_SELECT;
            break;
        case 2:
            PR_ENC_SELECT;
            break;
        default:
            break;
        }
    }
    else if (STORAGE_SPI_INDEX == spi_index)
    {
        switch (device_id)
        {
        case 1:
            FRAM_DEV_SELECT;
            break;
        case 2:
            OUTER_FLASH_DEV_SELECT;
            break;
        default:
            break;
        }        

    }
    g_spi_ctrl[spi_index].is_busy = BUSY;
}


/**
 * @brief 释放占用的SPI总线，拉高对应片选
 * 0 表示不忙  1表示忙
 * @param spi_id SPI总线序号
 * @param device_id 设备序号
 */
void bsp_spiBusExit(uint8_t spi_id, uint8_t device_id)
{
    // 增加了入口参数device_id，使得在一条SPI总线上可以挂多个设备
    int16_t spi_index = bsp_getSpiIndex(spi_id);
    if (ENC_SPI_INDEX == spi_index)
    {
        switch (device_id)
        {
        case 1:
            JOINT_ENC_UNSELECT;
            break;
        case 2:
            PR_ENC_UNSELECT;
            break;
        default:
            break;
        }
    }
    else if (STORAGE_SPI_INDEX == spi_index)
    {
        switch (device_id)
        {
        case 1:
            FRAM_DEV_UNSELECT;
            break;
        case 2:
            OUTER_FLASH_DEV_UNSELECT;
            break;
        default:
            break;
        }
    }
    g_spi_ctrl[spi_index].is_busy = IDLE;
}


/**
 * @brief 判断SPI总线忙，方法是检测其他SPI芯片的片选信号是否为1
 * 
 * @return uint8_t 0 表示不忙  1表示忙
 */
uint8_t bsp_isSpiBusBusy(uint8_t spi_id)
{
    int16_t spi_index = bsp_getSpiIndex(spi_id);
    return g_spi_ctrl[spi_index].is_busy;
}

